﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace SerialChart
{
    /// <summary>
    /// 串口辅助类
    /// 完成底层串口通信，为上层协议解析数据发送提供接口
    /// </summary>
    public class SerialHelper : IFrameStream
    {
        #region 变量
        private SerialPort serialPort = new SerialPort();//串口控件

        public Common.RingBuffer<Byte> Buff = new Common.RingBuffer<byte>();//串口接收数据缓冲区
        public DataParser parser = null;//数据解析器

        public int available
        {
            get { return Buff.Available; }
        }

        public string PortName
        {
            get;
            set;
        }
        public int BaudRate
        {
            get;
            set;
        }
        #endregion

        #region 构造函数与析构函数

        public SerialHelper()
            : this("COM1", 115200)
        {
        }

        public SerialHelper(string portName)
            : this(portName, 115200)
        {
        }

        public SerialHelper(string portName, int baudRate)
        {
            PortName = portName;
            BaudRate = baudRate;
            this.serialPort.ReceivedBytesThreshold = 1;//事件驱动触发
            serialPort.DataReceived += SerialPort_DataReceived;//数据到达事件绑定
        }

        ~SerialHelper()
        {
            Stop();
            serialPort.Dispose();
        }

        #endregion

        #region 串口底层操作
        public void SerialSetPortName(string portName)
        {
            PortName = portName;
        }

        public void SerialSetBaudRate(int baudRate)
        {
            BaudRate = baudRate;
        }

        public void SerialOpen()
        {
            try
            {
                serialPort.PortName = PortName;
                serialPort.BaudRate = BaudRate;
                //serialPort.Parity = Parity.Even; //为什么加上后数据乱码？？？设置应该没有错
                //serialPort.DataBits = 8;
                //serialPort.StopBits = StopBits.One;
                //serialPort.ReadTimeout = -1;
                if (serialPort.IsOpen)
                {
                    SerialClose();
                }
                if (SerialPort.GetPortNames().Contains(PortName))//存在对应串口
                {
                    serialPort.Open();
                }
                else
                {
                    MessageBox.Show("串口" + PortName + "不存在或无法打开");
                }
            }
            catch (Exception)
            {
                MessageBox.Show("串口" + PortName + "不存在或无法打开");
            }
        }

        public void SerialClose()
        {
            try
            {
                if (serialPort.IsOpen == true)
                {
                    serialPort.Close();
                }
            }
            catch (Exception)
            {

                MessageBox.Show("串口关闭失败");
            }
           
        }

        public void SerialWrite(Byte[] buff)
        {
            if (serialPort.IsOpen)
            {
                serialPort.Write(buff, 0, buff.Length);
            }
        }

        public int SerialRead(char[] buffer, int offset, int count)
        {
            return serialPort.Read(buffer, offset, count);
        }
        #endregion

        #region 实现接口

        public void Start()
        {
            SerialOpen();
        }

        public void Stop()
        {
            SerialClose();
        }

        public Byte Read()
        {
            //读取一个字节，待实现？？？
            byte[] buf = new byte[1];
            if (Buff.Available > 0)
            {
                Buff.Read(buf, 0, 1);
                return buf[0];
            }
            else
                throw new Exception("Buff is empty!");
        }
        /// <summary>
        /// 阻塞函数
        /// 未实现
        /// </summary>
        /// <returns></returns>
        public string ReadLine()
        {
            StringBuilder sb = new StringBuilder();
            bool isReading = true;
            while (isReading)
            {
                char aa;
                if (Buff.Available > 0)
                    aa = (char)Read();
                else
                    continue;
                if (aa != 0x0d && aa != 0x0a)
                    sb.Append((char)aa);
                else
                {
                    if (sb.Length > 0)
                        isReading = false;
                    else
                        continue;
                }
            }
            return sb.ToString();
        }

        public void Send(Byte[] bytes)
        {
            SerialWrite(bytes);
        }

        #endregion

        /// <summary>
        /// 通过事件获取串口接收到的数据
        /// 如果挂载了解析器则直接由解析器解析数据，否则数据存入缓冲区等待读取
        /// 稳定性需要测试？？？不能保证
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (serialPort.IsOpen)//串口是开启的
            {
                try
                {
                    int readlen = serialPort.BytesToRead;
                    if (readlen > 0)
                    {
                        byte[] readBuffer = new byte[readlen];
                        int count = serialPort.Read(readBuffer, 0, readlen);
                        if (parser != null)  //如果挂载了解析器
                        {
                            parser.GetData(readBuffer);
                        }
                        else    //未挂载解析器，数据存入缓冲区（缓冲区大小固定，会溢出）
                        {
                            Buff.Write(readBuffer, 0, count);
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }

            }
        }
    }

    public interface DataParser
    { 
        void GetData(Byte[] data);
    }
}
